package server;

import java.util.ArrayList;

import util.MyParser;

public class SessionThread extends Thread {
	private Game gt;
	private int painterIndex = 0;
	private int id;
	private ArrayList<Participant> pl;
	private ArrayList<ReceiveThread> rtl;
	private ReceiveMonitor rm;
	private ReceiveMonitor serverrm;
	private String[] wordlist;
	private int winner = -1;
	private int currentPainter;
	private int round;
	private int nbrPlayers;
	private boolean hasStarted;
	public static int TIME_OUT = Integer.MIN_VALUE;
	public static int PAINTER_DISCONNECTED = Integer.MAX_VALUE;
	public static int UPDATE_PAINTER = Integer.MAX_VALUE - 1;
	public static int NOT_ENOUGH_PLAYERS = Integer.MAX_VALUE - 2;

	public SessionThread(int id, Participant p, String[] wordlist, int round,
			ReceiveThread rt, int nbrPlayers, ReceiveMonitor serverrm) {
		this.id = id;
		this.serverrm = serverrm;
		pl = new ArrayList<Participant>();
		rtl = new ArrayList<ReceiveThread>();
		pl.add(p);

		rtl.add(rt);
		this.wordlist = wordlist;
		this.nbrPlayers = nbrPlayers;
		rm = new ReceiveMonitor();
		hasStarted = false;
		if (round > 0) {
			this.round = round;
		} else {
			round = 1;
		}
	}

	public void run() {
		for (int i = 0; i < rtl.size(); i++) {
			rtl.get(i).setReceiveMonitor(rm);
		}
		enterLobbyMode();
		gt = new Game(pl, rm, serverrm, id, 100);
		int turns = pl.size() * round;
		ServerSend.serverGameSendToAll(pl, getScoreList());
		while (turns > 0) {
			if (pl.size() > 1) {
				currentPainter = getPainter();
				String temp = rndWord();

				gt.setCurrentWord(temp);
				gt.setCurrentPainter(currentPainter);
				winner = gt.run();
				if (winner == PAINTER_DISCONNECTED) {
					turns--;
				} else if (winner == TIME_OUT) {
					turns--;
					ServerSend.serverChatSendToAll(pl, pl.get(currentPainter)
							.getName()
							+ " failed to paint " + temp);

				} else if (winner == UPDATE_PAINTER) {
					currentPainter--;
				} else if (winner == NOT_ENOUGH_PLAYERS) {
					turns = 0;
				} else {
					Participant w = pl.get(winner);
					int t = gt.getTime();
					if (w != null) {
						w.addScore(t / 10 + 2);
					}
					w = pl.get(currentPainter);
					if (w != null) {
						w.addScore(t / 10);
					}
					turns--;
					ServerSend.serverChatSendToAll(pl, "The correct word was "
							+ temp);
				}
				if (currentPainter < pl.size()) {
					ServerSend.sendToPlayer(pl, currentPainter, MyParser
							.codeToGame("notpaintmaster"));
				}
				ServerSend.serverGameSendToAll(pl, getScoreList());
			} else {
				turns = 0;
			}
		}
		scoreSort();
		gt.terminateThreads();
		finished();
	}

	public void enterLobbyMode() {
		ServerSend.serverChatSendToAll(pl, "Welcome to the lobby!");
		String s = null;

		do {
			s = rm.getMessage();
			if (MyParser.isGame(s)) {
				if (MyParser.getMessage(s).equals("startgame")
						&& MyParser.getName(s).equals(pl.get(0).getName())) {
					if (pl.size() >= 2) {
						ServerSend.sendToAll(pl, MyParser.codeToChat(
								"Not enough players to start the game!",
								"Server"));
					}
					hasStarted = true;
				} else if (MyParser.getMessage(s).equals("leavegame")) {
					if (pl.size() - 1 == 0) {
						finished();
					} else {
						serverrm.setMessage(MyParser.SERVER + MyParser.FIELD
								+ "exitgame" + MyParser.FIELD + id, MyParser
								.getName(s));
						ServerSend.sendToAll(pl, MyParser.codeToChat(MyParser
								.getName(s)
								+ " has left the lobby!", "Server"));
					}
				}
			}
			if (MyParser.isChat(s)) {
				ServerSend.sendToAll(pl, s);
			}
		} while (!hasStarted);

	}

	public String rndWord() {
		int rnd = (int) ((wordlist.length) * Math.random());
		String temp = wordlist[rnd];
		String[] newWordlist = new String[wordlist.length - 1];

		for (int i = 0; i < rnd; i++) {
			newWordlist[i] = wordlist[i];
		}
		for (int i = rnd + 1; i < wordlist.length; i++) {
			newWordlist[i - 1] = wordlist[i];
		}
		wordlist = newWordlist;
		return temp;
	}

	public int getPainter() {
		int temp = painterIndex;
		painterIndex++;
		return temp % pl.size();
	}

	public void scoreSort() {
		boolean swapped = false;
		do {
			swapped = false;
			for (int i = 1; i < pl.size(); i++) {
				if (pl.get(i - 1).getScore() < pl.get(i).getScore()) {
					Participant temp = pl.get(i - 1);
					pl.set(i - 1, pl.get(i));
					pl.set(i, temp);
					swapped = true;
				}
			}
		} while (swapped);
	}

	public String getScoreList() {
		StringBuilder sb = new StringBuilder();
		sb.append("scores" + MyParser.FIELD);
		for (int i = 0; i < pl.size(); i++) {
			sb.append(pl.get(i).getName() + MyParser.DATA
					+ pl.get(i).getScore() + MyParser.DATA);
		}
		return sb.toString();
	}

	public boolean addParticipant(Participant p, ReceiveThread rt) {
		if (pl.size() < nbrPlayers) {
			pl.add(p);
			rt.setReceiveMonitor(rm);
			rtl.add(rt);
			ServerSend.serverChatSendToAll(pl, p.getName()
					+ " has joined the session!");
			return true;
		}
		return false;
	}

	private void finished() {
		serverrm.setMessage(MyParser.SERVER + MyParser.FIELD + "endofgame",
				String.valueOf(id));
		ServerSend.serverGameSendToAll(pl, "endofsession");

		for (int i = 0; i < rtl.size(); i++) {
			rtl.get(i).setReceiveMonitor(serverrm);
			pl.get(i).resetScore();
		}
	}

	public int getID() {
		return id;
	}

	public ArrayList<Participant> getParticpants() {
		return pl;
	}

	public ArrayList<ReceiveThread> getReceiveThread() {
		return rtl;
	}

	public boolean hasStarted() {
		return hasStarted;
	}

	public boolean isFull() {
		return pl.size() == nbrPlayers;
	}

}
